import {Matrix4} from 'three';
import Constant from './ui-constant';

let _ivl=200;
const _timer=new Float32Array(2);
const _components=[];
const _requestedUpdates={};
const _trs=new Matrix4();

export default class UIUpdateManager{

    static set interval(_int){
        _ivl=_int;
    }

    static update(renderer,uiContainer){
        if(!uiContainer)return;
        if(uiContainer.isTop){
            renderer.clearDepth();
        }
        if(uiContainer.layout===Constant.LAYOUT_RELATIVE){
            _trs.copy(uiContainer.matrixWorld).invert();
            uiContainer.applyMatrix4(_trs);
            uiContainer.applyMatrix4(uiContainer.camera.matrixWorld);
        }
        renderer.render(uiContainer.scene,uiContainer.camera);

        _timer[1]=performance.now();
        if((_timer[1]-_timer[0])<_ivl)return;
        _timer[0]=_timer[1];

        if ( Object.keys( _requestedUpdates ).length > 0 ) {
            const roots = _components.filter( ( component ) => {
                return !component.getUIParent();
            } );
            roots.forEach( root => UIUpdateManager.traverseParsing( root ) );
            roots.forEach( root => UIUpdateManager.traverseUpdates( root ) );
        }
    }

    static register( component ) {
        if ( !_components.includes(component) ) {
            _components.push( component );
        }
    }

    static requestUpdate( component, updateParsing, updateLayout, updateInner ) {
        component.traverse( (child)=> {
            if ( !child.isUI ) return;
            if ( !_requestedUpdates[ child.id ] ) {
                _requestedUpdates[ child.id ] = {
                    updateParsing,
                    updateLayout,
                    updateInner,
                    needCallback: ( updateParsing || updateLayout || updateInner )
                };
            } else {
                if (updateParsing)_requestedUpdates[ child.id ].updateParsing = true;
                if (updateLayout)_requestedUpdates[ child.id ].updateLayout = true;
                if (updateInner) _requestedUpdates[ child.id ].updateInner = true;
            }
        });
    }
    static disposeOf( component ) {
        const idx = _components.indexOf( component );
        if ( idx > -1 ) {
            _components.splice( idx, 1 );
        }
    }
    static traverseParsing( component ) {
        const request = _requestedUpdates[ component.id ];
        if ( request && request.updateParsing ) {
            component.parseParams();
            request.updateParsing = false;
        }
        component.getUIChildren().forEach( child => UIUpdateManager.traverseParsing( child ) );
    }
    static traverseUpdates( component ) {
        const request = _requestedUpdates[ component.id ]
        if ( request && request.updateLayout ) {
            request.updateLayout = false;
            component.updateLayout();
        }
        if ( request && request.updateInner ) {
            request.updateInner = false;
            component.updateInner();
        }
        if ( request && request.needCallback ) {
            component.onAfterUpdate();
        }
        delete _requestedUpdates[ component.id ];
        component.getUIChildren().forEach( ( childUI ) => {
            UIUpdateManager.traverseUpdates( childUI );
        } );
    }
    static deepDelete( object3D ) {
        object3D.children.forEach( (child)=> {
            if ( child.children.length > 0 ) UIUpdateManager.deepDelete( child );
            object3D.remove( child );
            UIUpdateManager.disposeOf( child );
            if ( child.material ) child.material.dispose();
            if ( child.geometry ) child.geometry.dispose();
        });
        object3D.children = [];
    }
    
}